package tf.mcs.exp;

import com.alibaba.excel.ExcelWriter;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * @Name ：ExcelUtil
 * @Description ：Excel操作工具类
 * @Author ：Zhiwei Wang
 * @Date ：2022/10/13 8:52
 * @Version ：$V1.0
 * @History ：
 */
@Slf4j
public class ExcelUtil {
    //默认每个sheet页的数据条数
    private static final Double SHEET_SIZE = 10000D;

    /**
     * @param :list      对象列表
     * @param :dir       文件存放目录
     * @param :excelName Excel文件名
     * @param :sheetName sheet页名
     * @param :clazz     对象类型
     * @return :String 文件全路径名
     * @Name :exportExcel
     * @Description :将对象列表导出到Excel
     * @Author :Zhiwei Wang
     * @Date :2022/10/13 14:26
     * @Version :1.0
     */
    public static String exportExcel(List list, String dir, String excelName, String sheetName, Class clazz) {
        log.info("开始创建Excel-{}", excelName);

        //创建sheet页的个数
        int sheetCount = (int) Math.ceil(list.size() / SHEET_SIZE);
        ExcelHandler handler = new ExcelHandler(dir);
        try (ExcelWriter writer = handler.create(excelName, clazz)) {
            List newList = new ArrayList(1024);
            for (int a = 0; a < sheetCount; a++) {
                Integer newCount = SHEET_SIZE.intValue();
                if (a == sheetCount - 1) {
                    newCount = list.size() - SHEET_SIZE.intValue() * a;
                }

                for (int i = 0; i < newCount; i++) {
                    newList.add(list.get(SHEET_SIZE.intValue() * a + i));
                }
                handler.write(writer, newList, sheetName + (a + 1));
                // 防止数据重复，及时情况list集合
                newList.clear();
            }
            return dir + File.separator + excelName + ".xlsx";
        } catch (Exception e) {
            log.error("导出Excel-{},失败：{}", excelName, e);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param :list      对象列表
     * @param :dir       文件存放目录
     * @param :excelName Excel文件名
     * @param :clazz     对象类型
     * @return :String 文件全路径名
     * @Name :exportExcel
     * @Description :将对象列表导出到Excel-不指定sheet名
     * @Author :Zhiwei Wang
     * @Date :2022/10/13 14:26
     * @Version :1.0
     */
    public static String exportExcel(List list, String dir, String excelName, Class clazz) {
        return exportExcel(list, dir, excelName, "sheet", clazz);
    }

    /**
     * @param ：dataList  List<Map>数据
     * @param ：headParm  导出的表头信息
     * @param ：dir       导出目录
     * @param ：excelName excel名
     * @param ：sheetName sheet名
     * @return :String 文件全路径名
     * @Name :exportExcel
     * @Description :将List-Map数据导出Excel
     * @Author :Zhiwei Wang
     * @Date :2022/10/13 15:55
     * @Version :1.0
     */
    public static String exportExcelObj(List<Map<String, Object>> dataList, List<ExcelColumn> headParm, String dir, String excelName, String sheetName) {
        log.info("开始创建Excel-{}", excelName);

        List<List<String>> headStr = new ArrayList<>();
        // listMap数据装换
        for (ExcelColumn column : headParm) {
            List<String> title = new ArrayList<>();
            title.add(column.getText());
            headStr.add(title);
        }

        List<List<Object>> list = new ArrayList<>();
        //设置导出的数据内容
        for (Map<String, Object> m : dataList) {
            List<Object> data = new ArrayList<>();
            // listMap数据装换
            for (ExcelColumn column : headParm) {
                data.add(m.get(column.getDataIndex()));
            }
            list.add(data);
        }

        // 创建sheet页的个数
        int sheetCount = (int) Math.ceil(list.size() / SHEET_SIZE);
        ExcelHandler handler = new ExcelHandler(dir);
        try (ExcelWriter writer = handler.create(excelName, headStr)) {
            List newList = new ArrayList(1024);
            for (int a = 0; a < sheetCount; a++) {
                Integer newCount = SHEET_SIZE.intValue();
                if (a == sheetCount - 1) {
                    newCount = list.size() - SHEET_SIZE.intValue() * a;
                }

                for (int i = 0; i < newCount; i++) {
                    newList.add(list.get(SHEET_SIZE.intValue() * a + i));
                }
                handler.write(writer, newList, sheetName + (a + 1));
                // 防止数据重复，及时情况list集合
                newList.clear();
            }
            return dir + File.separator + excelName + ".xlsx";
        } catch (Exception e) {
            log.error("导出Excel-{},失败：{}", excelName, e);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param ：dataList  List<Map>数据
     * @param ：headParm  导出的表头信息
     * @param ：dir       导出目录
     * @param ：excelName excel名
     * @return :String 文件全路径名
     * @Name :exportExcel
     * @Description :将List-Map数据导出Excel-不指定sheet名
     * @Author :Zhiwei Wang
     * @Date :2022/10/13 15:55
     * @Version :1.0
     */
    public static String exportExcelObj(List<Map<String, Object>> dataList, List<ExcelColumn> headParm, String dir, String excelName) {
        return exportExcelObj(dataList, headParm, dir, excelName, "sheet");
    }

    public static String exportExcel(List<Map<String, Object>> dataList, List<Map> headParm, String dir, String excelName, String sheetName) throws Exception {
        List<ExcelColumn> list = new ArrayList<>();
        for (Map m : headParm) {
            ExcelColumn column = null;
            try {
                column = (ExcelColumn) map2Obj(m, ExcelColumn.class);
            } catch (Exception e) {
                e.printStackTrace();
                return "headParm不正确";
            }
            list.add(column);
        }
        return exportExcelObj(dataList, list, dir, excelName, sheetName);
    }

    public static String exportExcel(List<Map<String, Object>> dataList, List<Map> headParm, String dir, String excelName) throws Exception {
        return exportExcel(dataList, headParm, dir, excelName, "sheet");
    }

    public static Object map2Obj(Map<String, Object> map, Class<?> clz) throws Exception {
        Object obj = clz.newInstance();
        Field[] declaredFields = obj.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                continue;
            }
            field.setAccessible(true);
            field.set(obj, map.get(field.getName()));
        }
        return obj;
    }
}
